#include "EngageManager.h"
// Unit includes
#include "UnitZergling.h"
//#include "UnitHydralisk.h"
//#include "UnitScourge.h"
//#include "UnitMutalisk.h"
using namespace BWAPI;

EngageManager* TheEngageManager = NULL;

// Constructor
EngageManager::EngageManager()
{
  // Set the instance
  TheEngageManager = this;

  // Set up all of our unit types mapped to their tactics
  this->tactics[UnitTypes::Zerg_Zergling] = new ZerglingTactics();

  // These are all default
  this->tactics[UnitTypes::Zerg_Hydralisk] = new UnitTactics();
  this->tactics[UnitTypes::Zerg_Mutalisk] = new UnitTactics();
  this->tactics[UnitTypes::Zerg_Scourge] = new UnitTactics();
  this->tactics[UnitTypes::Zerg_Defiler] = new UnitTactics();
  this->tactics[UnitTypes::Zerg_Lurker] = new UnitTactics();
  this->tactics[UnitTypes::Zerg_Ultralisk] = new UnitTactics();
  this->tactics[UnitTypes::Zerg_Devourer] = new UnitTactics();
  this->tactics[UnitTypes::Zerg_Guardian] = new UnitTactics();
  this->tactics[UnitTypes::Zerg_Queen] = new UnitTactics();
}

// Destructor
EngageManager::~EngageManager()
{
  for each (std::pair<UnitType, UnitTactics*> entry in this->tactics) {
    delete entry.second;
  }
}

// create: returns the extern instance or creates one if it was not initialized
EngageManager* EngageManager::create()
{
  if (TheEngageManager) return TheEngageManager;
  return new EngageManager();
}

// destroy: removes the original EngageManager
void EngageManager::destroy()
{
  if (TheEngageManager) 
    delete TheEngageManager;
}

// onUnitDestroy: Called when a unit is destroyed so the memory may be freed
void EngageManager::onUnitDestroy(Unit* unit)
{
  this->dismiss(unit);
}

// update: Use all indexed units to engage towards their target
void EngageManager::update()
{
  if (Broodwar->getFrameCount() % 4 == 0) {
    for each (std::pair<Unit*, UnitState*> unit in this->states){
      this->tactics[unit.first->getType()]->update(unit.second);
    }
  }
}

// engage: Triggers a unit or unit for iterative engagement
void EngageManager::engage(Unit* unit, Position target, EngageType method)
{
  // Return if this does not belong to us
  if (unit->getPlayer() != Broodwar->self())
    return;

  // Return if this is a unit we don't know how to control
  UnitType type = unit->getType();
  if (tactics.find(type) == tactics.end())
    return;

  // Build the object if we are not already using this unit for engagement
  if (this->states.find(unit) == this->states.end()) {
    this->states[unit] = this->tactics[type]->newState();
  }

  // Update information
  this->states[unit]->unit = unit;
  this->states[unit]->target = target;
  this->states[unit]->method = method;
  this->states[unit]->priority = 0;
}

void EngageManager::engage(std::set<Unit*> units, Position target, EngageType method)
{
  for each (Unit* u in units) {
    this->engage(u, target, method);
  }
}

void EngageManager::dismiss(Unit* unit)
{
  // Make sure the unit is being controlled
  if (states.find(unit) == states.end())
    return;

  tactics[unit->getType()]->delState(this->states[unit]);
  this->states.erase(unit);
}

void EngageManager::dismiss(std::set<Unit*> units)
{
  for each (Unit* u in units) {
    this->dismiss(u);
  }
}

